package asapIs134CK.womi.client.games.logoGame.froggitTheFrog;

import asapIs134CK.womi.client.games.logoGame.froggitTheFrog.cellsImpl.FroggitEnd;
import asapIs134CK.womi.client.games.logoGame.froggitTheFrog.cellsImpl.FroggitSand;
import asapIs134CK.womi.client.games.logoGame.froggitTheFrog.cellsImpl.FroggitStart;
import asapIs134CK.womi.client.games.logoGame.froggitTheFrog.cellsImpl.FroggitWall;
import asapIs134CK.womi.client.games.logoGame.utils.Position;
import asapIs134CK.womi.client.games.logoGame.utils.exceptions.ValueException;

import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Image;

/**
 * Represent the world for basic froggit game
 * @author LeoJ
 * NOTE on conventions :
 * Cell[][] is a matrix that regroup the map cells.
 * 	axis are :
 * 		- first	 	y for the row number
 * 		- second	x for the column number
 * 
 * origin is on the top left
 */
public class FroggitWorld {
	private Cell[][] _map;
	private FlexTable _table;
	private FlexTable _imageTable;
	private Position _start;
	private String _name;
	
	public final static int DEFAULT_SIZE = 10;
	
	public FroggitWorld(){
		_map = new Cell[DEFAULT_SIZE][DEFAULT_SIZE];
		_table = new FlexTable();
		_imageTable = new FlexTable();
		_start = new Position(0, 0);
		_name = "Default Map";
		initToDefaultMap();
		initGUI();
		initImageGUI();
	}
	
	public FroggitWorld(Cell[][] specificMap, Position startPos, String name) throws ValueException{
		_map = specificMap;
		_table = new FlexTable();
		_imageTable = new FlexTable();
		_start = startPos;
		_name = name;
		if(_map[_start.getY()][_start.getX()] instanceof FroggitStart){
			//OK !
		}else{
			throw new ValueException("the given start position does not match a StartCell ...");
		}
		initGUI();
		initImageGUI();
	}
	
	private void initToDefaultMap(){
		//first fill with Sand
		for(int i = 0; i< _map.length; i++){
			Cell[] row = _map[i];
			for(int j = 0; j< row.length; j++){
				row[j] = new FroggitSand();
			}
		}
		//then replace sand by wall where it 's needed
		_map[0][0]= new FroggitStart();
		_map[0][1]= new FroggitWall();
		_map[0][6]= new FroggitWall();
		_map[1][1]= new FroggitWall();
		_map[1][6]= new FroggitWall();
		_map[2][1]= new FroggitWall();
		_map[2][6]= new FroggitWall();
		_map[3][8]= new FroggitWall();
		_map[4][0]= new FroggitWall();
		_map[4][1]= new FroggitWall();
		_map[4][2]= new FroggitWall();
		_map[4][3]= new FroggitWall();
		_map[4][4]= new FroggitWall();
		_map[5][6]= new FroggitWall();
		_map[6][1]= new FroggitWall();
		_map[6][2]= new FroggitWall();
		_map[6][3]= new FroggitWall();
		_map[6][4]= new FroggitWall();
		_map[6][5]= new FroggitWall();
		_map[6][6]= new FroggitWall();
		_map[7][5]= new FroggitWall();
		_map[7][7]= new FroggitWall();
		_map[7][9]= new FroggitWall();
		_map[8][3]= new FroggitWall();
		_map[9][3]= new FroggitWall();
		_map[DEFAULT_SIZE-1][DEFAULT_SIZE-1] = new FroggitEnd();
	}
	
	public FroggitReaction handleSuperpositionWith(FroggitMyFrog littleFrog) {
		Position pos = littleFrog.getPosition();
		FroggitReaction result = null;
		if(isInsideMap(pos)){
			result = _map[pos.getY()][pos.getX()].handleSuperpositionWith(littleFrog);
		}else{
			result = FroggitReaction.Fail;
		}
		return result;
	}
	
	
	private boolean isInsideMap(Position pos) {
		boolean isInside = true;
		int x = pos.getX();
		int y = pos.getY();
		if(y < 0 || y >= _map.length){
			isInside = false;
		}
		if(isInside && (x < 0 || x >= _map[y].length)){
			isInside = false;
		}
		//System.out.println("isInside = "+isInside);
		return isInside;
	}

	@Override
	public String toString() {
		return toStringProcess("\n");
	}
	public String toHTMLString(){
		return toStringProcess("<br>");
	}
	private String toStringProcess(String breakLine){
		String basicPrintOut = "";
		basicPrintOut += "*******************************"+breakLine;
		basicPrintOut += "\tSize="+_map.length+"x"+_map[0].length+breakLine;
		basicPrintOut += "*******************************"+breakLine;
		
		for(int y = 0; y < _map.length; y++){
			Cell[] row = _map[y];
			for(int x = 0; x < row.length; x++){
				basicPrintOut+=row[x].toString()+" ";
			}
			basicPrintOut+=breakLine;
		}
		basicPrintOut += "*******************************"+breakLine;
		
		return basicPrintOut;
	}

	public FlexTable getTableRepresentation(){
		return _table;
	}
	public FlexTable getImageTableRepresentation(){
		return _imageTable;
	}
	
	/*usefull for more advance interaction between 
	 * the world and our froggit ...
	 * 
	 * not used for now ...
	 */
	@SuppressWarnings("unused")
	private void updateGUI(){}
	
	private void initGUI(){
		for(int i = 0; i<= _map.length; i++){
			_table.insertRow(i);
			_table.setText(i, 0, "r"+i);	
		}
		int firstRowSLength = _map[0].length;
		for(int i = 0; i <= firstRowSLength; i++){
			_table.setText(0, i, "c"+i);
		}
		
		for(int idx_row = 0; idx_row < _map.length; idx_row++){
			Cell[] currentRow = _map[idx_row];
			for(int idx_col = 0; idx_col< currentRow.length; idx_col++){
				_table.setText(idx_row+1, idx_col+1, 
						currentRow[idx_col].toString());
			}
		}
	}

	private void initImageGUI(){
		_imageTable.insertRow(0);
		for(int i = 1; i<= _map.length; i++){
			_imageTable.insertRow(i);
			_imageTable.setText(i, 0, "r"+i);	
		}
		int firstRowSLength = _map[0].length;
		for(int i = 1; i <= firstRowSLength; i++){
			_imageTable.setText(0, i, "c"+i);
		}
		
		for(int idx_row = 0; idx_row < _map.length; idx_row++){
			Cell[] currentRow = _map[idx_row];
			for(int idx_col = 0; idx_col< currentRow.length; idx_col++){
				_imageTable.setWidget(idx_row+1, idx_col+1, 
						currentRow[idx_col].getImage());
			}
		}
		//System.out.println("World:initImageGUI -> over !");
		
	}
	public String getCellString(int x, int y) {
		return _map[y][x].toString();
	}

	public Image getCellImage(int x, int y) {
		return _map[x][y].getImage();
	}

	public Position getStartPosition() {
		return _start;
	}

	public String getName() {
		return _name;
	}

	
}
